package cmd

import (
	"context"
	"fmt"
	"path"

	// "gitee.com/quantum-force/of-generic/safe"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/chromedp"
	"github.com/chromedp/chromedp/device"
)

type ShopCrawlInfo struct {
	ID              string   `json:"shop_id"`
	Name            string   `json:"name"`
	Address         string   `json:"address"`
	RecommandDishes []string `json:"recommend_dishes"`
}

func (tr *TaskRunner) FetchShops(url, file string) *TaskRunner {
	referer := dpIndexPage
	if len(url) > 0 {
		tr.tasks = append(tr.tasks, chromedp.Tasks{
			tr.FetchShopInfoByUrl(url, referer),
			tr.dumpShopInfo(),
			tr.shopReset(),
		})
		tr.Reset()
	} else if len(file) > 0 {
		shopUrls, err := tr.ReadLines(file)
		if err != nil {
			slog.Panicln("readFile err:", err)
			return tr
		}
		for _, url := range shopUrls {
			if len(url) == 0 {
				continue
			}
			tr.tasks = append(tr.tasks, Sequence(
				tr.FetchShopInfoByUrl(url, referer),
				tr.dumpShopInfo(),
				tr.shopReset(),
				tr.wait(randOver(2, 5)),
			))
			tr.Reset()
		}
	}

	return tr
}

func (tr *TaskRunner) FetchShopInfoByUrl(url, referer string) chromedp.ActionFunc {
	selShopName := `#basic-info > h1`
	selShopAddress := `#address`
	selRecommendDishesBox := "#shop-tabs > div.shop-tab-recommend.J-panel > ul"
	selRecommendDishes := `#shop-tabs > div.shop-tab-recommend.J-panel > ul > li`
	// selRecommendDisheNameTpl := `#shop-tabs > div.shop-tab-recommend.J-panel > ul > li:nth-child(%d) > p`
	return func(ctx context.Context) error {
		var dish string
		shopID := path.Base(url)
		tr.shopInfo.ID = shopID
		slog.Debugf("FetchShopInfoByUrl shopID:%s, tr.shopInfo.ID:%s", shopID, tr.shopInfo.ID)
		return chromedp.Run(ctx,
			chromedp.Navigate(url),
			tr.navigateWithRefererAction(url, referer),
			chromedp.Emulate(device.IPhone12Pro),
			IfPresent(
				selShopName,
				Sequence(
					// chromedp.WaitVisible(selShopName, chromedp.ByID),
					ScreenshotElemAndDump(selShopName,
						fmt.Sprintf(`tmp/shop_%s/name.png`, shopID),
						tr, &tr.shopInfo.Name),
					chromedp.ActionFunc(func(ctx context.Context) error {
						tr.shopInfo.Name = CutoffShopNameTextTail(RemoveEmtpy(tr.shopInfo.Name))
						slog.Debugf("shop-name:%s", tr.shopInfo.Name)
						return nil
					}),
				),
			),
			IfPresent(
				selShopAddress,
				Sequence(
					// chromedp.WaitVisible(selShopAddress, chromedp.ByID),
					ScreenshotElemAndDump(selShopAddress,
						fmt.Sprintf(`tmp/shop_%s/address.png`, shopID),
						tr, &tr.shopInfo.Address),
					chromedp.ActionFunc(func(ctx context.Context) error {
						tr.shopInfo.Address = RemoveEmtpy(tr.shopInfo.Address)
						slog.Debugf("shop-address:%s", tr.shopInfo.Name)
						return nil
					}),
				),
			),
			IfPresent(
				selRecommendDishesBox,
				Sequence(
					chromedp.SetAttributeValue(selRecommendDishesBox, "style", "height:888px;", chromedp.ByID),
					chromedp.SetAttributeValue(`#shop-tabs > div.shop-tab-recommend.J-panel > ul > li > p`, "style", "width:110px;", chromedp.ByQueryAll),
					Iter(
						selRecommendDishes,
						IterNodeNextFunc(func(ctx context.Context, idx int, node *cdp.Node) chromedp.Action {
							return Sequence(
								ScreenshotElemAndDump("p.name",
									fmt.Sprintf(`tmp/shop_%s/dish-%d.png`, shopID, idx),
									tr, &dish, chromedp.FromNode(node)),
								chromedp.ActionFunc(func(ctx context.Context) error {
									tr.shopInfo.RecommandDishes = append(tr.shopInfo.RecommandDishes, RemoveThreeDot(RemoveEmtpy(dish)))
									return nil
								}),
							)
						}),
						IterDoneFunc(func(ctx context.Context, matchAll bool) chromedp.Action {
							return chromedp.ActionFunc(func(ctx context.Context) error {
								fmt.Printf("extract all recommend dishes(%d)\n", len(tr.shopInfo.RecommandDishes))
								return nil
							})
						}),
					),
				),
			),
		)
	}
}

func (tr *TaskRunner) DumpShopInfo() *TaskRunner {
	tr.tasks = append(tr.tasks,
		tr.dumpShopInfo(),
	)
	return tr
}

func (tr *TaskRunner) dumpShopInfo() chromedp.ActionFunc {
	return func(ctx context.Context) error {
		slog.Debugf("dumpShopInfo shopID=>%+v", tr.shopInfo)
		file := fmt.Sprintf("crawled/shop/%s.json", tr.shopInfo.ID)
		return tr.dumpToFile(file, tr.shopInfo)
	}
}

func (tr *TaskRunner) ShopReset() *TaskRunner {
	tr.tasks = append(tr.tasks,
		tr.shopReset(),
	)
	return tr.Reset()
}

func (tr *TaskRunner) shopReset() chromedp.ActionFunc {
	return func(ctx context.Context) error {
		slog.Debugln("shopReset...")
		tr.shopInfo.ID = ""
		tr.shopInfo.Name = ""
		tr.shopInfo.Address = ""
		tr.shopInfo.RecommandDishes = nil
		return nil
	}
}
